MongoDB on AWS Cloud その4:Configサーバをレプリカセットに移行する
こんにちは、菊池です。
MongoDB on AWS 第4弾です。前回アップグレードした環境を使い、MongoDB 3.2 の新機能であるConfigサーバのレプリカセット構成を試します。
過去の記事:
- AWSクイックスタート:MongoDB on the AWS Cloudを試してみた
- MongoDB on AWS Cloud その2:ストレージエンジンをWiredTigerにしてみた
- MongoDB on AWS Cloud その3:Upgrade to MongoDB 3.2
はじめに
作業の前提条件と手順のサマリです。
前提条件
- Configサーバ、mongosはVer. 3.2.10
- Configサーバは3台(Config0/1/2)の独立構成で、ストレージエンジンはMMAPv1で稼働
手順サマリ
公式のドキュメントに記載の手順に従って進めます。マニュアルには、サービスを停止して行う手順と、Ver.3.2.4以降でサポートされたオンラインで実施する手順が記載されています。
今回の環境はVer.3.2.10なので、オンラインで可能な手順で実施していきます。
- Balancerの停止
- Configサーバの1台(Config0)をレプリカセットに変更(シングル)
- Configサーバを3台追加起動(Config3/4/5)し、2.のレプリカセットに追加
- 2.で最初にレプリカセットに変更したConfigサーバ(Config0)をレプリカセットから削除
- mongosの接続先をレプリカセットに変更
- 元から稼働していたConfigサーバ(Config0/1/2)を停止
- Balancerの再開
要は、既存のConfigサーバを1台と新規のConfigサーバ3台でレプリカセットを作り、mongosをそちらに向けた後に既存のConfigサーバを削除する流れになります。
注意事項
- レプリカセットに追加するConfig3/4/5は、必ず新規で構築しましょう。既存のConfig1/2をレプリカセットに追加しようとするとmongosが落ちました。
- mongosのログを常に確認し、異常がないか見ながら作業をしてください。
移行手順
1. Balancer停止
まずは事前作業として、シャーディング時にデータチャンクを移動させる働きを持つBalancerを停止します。mongosにログイン(今回の構成ではPrimaryノードで起動)し、sh.getBalancerState()
でBalancerの状態確認、sh.stopBalancer()
で停止します。
$ mongo MongoDB shell version: 3.2.10 connecting to: test mongos> sh.stopBalancer() Waiting for active hosts... Waiting for the balancer lock... Waiting again for active hosts after balancer is off... WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) mongos> sh.getBalancerState() false mongos>
2. Config0をレプリカセットに変更
Config0にログインし、1台のみのレプリカセットに変更します。まずはrs.initiate
でレプリカセットの初期化をします。
$ mongo localhost:27030 MongoDB shell version: 3.2.10 connecting to: localhost:27030/test configsvr> rs.initiate( { ... _id: "csReplSet", ... configsvr: true, ... version: 1, ... members: [ { _id: 0, host: "10.0.2.124:27030" } ] ... } ) { "ok" : 1 } configsvr>
Config0の設定ファイル/etc/mongod.conf
を修正し、一度再起動します。
net: port: 27030 systemLog: destination: file logAppend: true path: /data/mongod.log storage: dbPath: /data journal: enabled: true processManagement: fork: true pidFilePath: /var/run/mongod/mongod.pid sharding: clusterRole: configsvr configsvrMode: sccc #追記 replication: replSetName: csReplSet #追記
$ sudo service mongod restart Stopping mongod: [ OK ] Starting mongod: [ OK ]
これで再度ログインすると、プロンプトが変化し1台のみのレプリカセットになっています。
$ mongo localhost:27030 MongoDB shell version: 3.2.10 connecting to: localhost:27030/test csReplSet:PRIMARY> rs.status() { "set" : "csReplSet", "date" : ISODate("2016-10-07T02:51:13.587Z"), "myState" : 1, "term" : NumberLong(1), "configsvr" : true, "heartbeatIntervalMillis" : NumberLong(2000), "members" : [ { "_id" : 0, "name" : "10.0.2.124:27030", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 22, "optime" : { "ts" : Timestamp(1475808670, 2), "t" : NumberLong(1) }, "optimeDate" : ISODate("2016-10-07T02:51:10Z"), "infoMessage" : "could not find member to sync from", "electionTime" : Timestamp(1475808651, 1), "electionDate" : ISODate("2016-10-07T02:50:51Z"), "configVersion" : 1, "self" : true } ], "ok" : 1 } csReplSet:PRIMARY>
3. 新規Configサーバを3台追加
次に、各サーバにConfigサーバを追加していきます。既存のConfigサーバが稼働するインスタンス上に追加でサーバを起動するようにします。以下のような設定ファイルを/etc/mongod0.conf
として作成しました。
$ cat /etc/mongod0.conf net: port: 27031 systemLog: destination: file logAppend: true path: /data/mongod0.log storage: dbPath: /data/wt journal: enabled: true processManagement: fork: true pidFilePath: /var/run/mongod/mongod0.pid sharding: clusterRole: configsvr replication: replSetName: csReplSet
また、既存の起動スクリプト/etc/init.d/mongod
をコピーし、/etc/init.d/mongod0
を作成しておきます。
$ sudo cp -p /etc/init.d/mongod /etc/init.d/mongod0
読み込む設定ファイルのみ/etc/mongod0.conf
に変更しておきましょう。
$ cat /etc/init.d/mongod0 | grep CONFIGFILE CONFIGFILE="/etc/mongod0.conf" OPTIONS=" -f $CONFIGFILE"
mongod0を起動します。
$ sudo service mongod0 start Starting mongod: [ OK ]
これを3台全てのConfigサーバで実施し、Config3/4/5とします。
再度、Config0に戻り、起動したConfig3/4/5をレプリカセットのメンバーとして追加します。
csReplSet:PRIMARY> rs.add( { host: "10.0.3.43:27031", priority: 0, votes: 0 } ) { "ok" : 1 } csReplSet:PRIMARY> rs.add( { host: "10.0.4.81:27031", priority: 0, votes: 0 } ) { "ok" : 1 } csReplSet:PRIMARY> rs.add( { host: "10.0.2.124:27031", priority: 0, votes: 0 } ) { "ok" : 1 } csReplSet:PRIMARY>
ここで、priority: 0, votes: 0
としておくことで、Primaryの選出には参加せず、昇格もしないメンバーとなります。
csReplSet:PRIMARY> rs.status() { "set" : "csReplSet", "date" : ISODate("2016-10-07T03:40:20.843Z"), "myState" : 1, "term" : NumberLong(1), "configsvr" : true, "heartbeatIntervalMillis" : NumberLong(2000), "members" : [ { "_id" : 0, "name" : "10.0.2.124:27030", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 2969, "optime" : { "ts" : Timestamp(1475811612, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2016-10-07T03:40:12Z"), "electionTime" : Timestamp(1475808651, 1), "electionDate" : ISODate("2016-10-07T02:50:51Z"), "configVersion" : 6, "self" : true }, { "_id" : 1, "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 947, "optime" : { "ts" : Timestamp(1475811612, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2016-10-07T03:40:12Z"), "lastHeartbeat" : ISODate("2016-10-07T03:40:18.943Z"), "lastHeartbeatRecv" : ISODate("2016-10-07T03:40:18.953Z"), "pingMs" : NumberLong(0), "syncingTo" : "10.0.2.124:27030", "configVersion" : 6 }, { "_id" : 2, "name" : "10.0.4.81:27031", "health" : 1, "state" : 2, "uptime" : 446, "optime" : { "ts" : Timestamp(1475811612, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2016-10-07T03:40:12Z"), "lastHeartbeat" : ISODate("2016-10-07T03:40:18.949Z"), "lastHeartbeatRecv" : ISODate("2016-10-07T03:40:18.968Z"), "pingMs" : NumberLong(2), "syncingTo" : "10.0.3.43:27031", "configVersion" : 6 }, { "_id" : 3, "name" : "10.0.2.124:27031", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 7, "optime" : { "ts" : Timestamp(1475811612, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2016-10-07T03:40:12Z"), "lastHeartbeat" : ISODate("2016-10-07T03:40:18.942Z"), "lastHeartbeatRecv" : ISODate("2016-10-07T03:40:18.965Z"), "pingMs" : NumberLong(0), "syncingTo" : "10.0.3.43:27031", "configVersion" : 6 } ], "ok" : 1 } csReplSet:PRIMARY>
追加した全てのメンバーが"SECONDARY"
となっていればデータの同期も完了です。なお、追加したConfigサーバは全てWiredTigerストレージエンジンでデータを保持しています。
レプリカセットの設定を変更し、全てのメンバーのPriorityとvotesを1とします。
csReplSet:PRIMARY> var cfg = rs.conf(); csReplSet:PRIMARY> cfg.members[0].priority = 1; 1 csReplSet:PRIMARY> cfg.members[1].priority = 1; 1 csReplSet:PRIMARY> cfg.members[2].priority = 1; 1 csReplSet:PRIMARY> cfg.members[3].priority = 1; 1 csReplSet:PRIMARY> cfg.members[0].votes = 1; 1 csReplSet:PRIMARY> cfg.members[1].votes = 1; 1 csReplSet:PRIMARY> cfg.members[2].votes = 1; 1 csReplSet:PRIMARY> cfg.members[3].votes = 1; 1 csReplSet:PRIMARY> rs.reconfig(cfg); { "ok" : 1 } csReplSet:PRIMARY>
4. Config0を切り離し
最初にレプリカセットのメンバーとなったConfig0を切り離します。まず、Config0でrs.stepDown
によりPrimaryから降格させます。
csReplSet:PRIMARY> rs.stepDown(600) 2016-10-07T03:42:40.457+0000 I NETWORK [thread1] reconnect localhost:27030 (127.0.0.1) ok csReplSet:SECONDARY>
次に設定ファイル/etc/mongod.conf
から、configsvrMode: sccc
の記述を削除し、再起動します。
net: port: 27030 systemLog: destination: file logAppend: true path: /data/mongod.log storage: dbPath: /data journal: enabled: true processManagement: fork: true pidFilePath: /var/run/mongod/mongod.pid sharding: clusterRole: configsvr configsvrMode: sccc # <- 削除 replication: replSetName: csReplSet
$ sudo service mongod restart Stopping mongod: [ OK ] Starting mongod: [ OK ]
これでレプリカセットの状態を確認すると、Config0のstateが"stateStr" : "REMOVED"
となり、新たに別のConfigサーバがPrimaryに選出されています。
csReplSet:SECONDARY> rs.status() { "set" : "csReplSet", "date" : ISODate("2016-10-07T03:47:25.537Z"), "myState" : 2, "term" : NumberLong(2), "syncingTo" : "10.0.2.124:27031", "configsvr" : true, "heartbeatIntervalMillis" : NumberLong(2000), "members" : [ { "_id" : 0, "name" : "10.0.2.124:27030", "health" : 1, "state" : 10, "stateStr" : "REMOVED", "uptime" : 34, "optime" : { "ts" : Timestamp(1475811769, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2016-10-07T03:42:49Z"), "lastHeartbeat" : ISODate("2016-10-07T03:47:25.095Z"), "lastHeartbeatRecv" : ISODate("2016-10-07T03:47:24.229Z"), "pingMs" : NumberLong(2), "syncingTo" : "10.0.2.124:27031", "configVersion" : 7 }, { "_id" : 1, "name" : "10.0.3.43:27031", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 871, "optime" : { "ts" : Timestamp(1475812042, 3), "t" : NumberLong(2) }, "optimeDate" : ISODate("2016-10-07T03:47:22Z"), "lastHeartbeat" : ISODate("2016-10-07T03:47:24.900Z"), "lastHeartbeatRecv" : ISODate("2016-10-07T03:47:24.947Z"), "pingMs" : NumberLong(2), "electionTime" : Timestamp(1475811768, 1), "electionDate" : ISODate("2016-10-07T03:42:48Z"), "configVersion" : 7 }, ~~~~~~~~~~~~~~~~~~~~省略~~~~~~~~~~~~~~~~~~~~
5. mongosの接続先変更
mongosの接続先をレプリカセットに変更します。/etc/mongos.conf
のconfigDB:
を、新たに作成したレプリカセットの接続先に書き換えます。
変更前:
net: port: 27017 systemLog: destination: file logAppend: true path: /log/mongos.log processManagement: fork: true pidFilePath: /var/run/mongod/mongos.pid sharding: configDB: 10.0.3.43:27030,10.0.4.81:27030,10.0.2.124:27030
変更後:
net: port: 27017 systemLog: destination: file logAppend: true path: /log/mongos.log processManagement: fork: true pidFilePath: /var/run/mongod/mongos.pid sharding: configDB: csReplSet/10.0.3.43:27031,10.0.4.81:27031,10.0.2.124:27031
mongosを再起動
$ sudo service mongos restart Stopping mongod: [ OK ] Starting mongod: [ OK ]
これでレプリカセットへの接続ができました。
6. Config0/1/2を停止
元々あったConfigサーバを停止します。まずはConfig0をレプリカセットから完全に削除します。新しいPrimaryにログインし、
csReplSet:PRIMARY> rs.remove("10.0.2.124:27030") { "ok" : 1 } csReplSet:PRIMARY>
これで新規に追加した3台のみのレプリカセットになりました。
csReplSet:PRIMARY> rs.status() { "set" : "csReplSet", "date" : ISODate("2016-10-07T03:53:10.578Z"), "myState" : 1, "term" : NumberLong(2), "configsvr" : true, "heartbeatIntervalMillis" : NumberLong(2000), "members" : [ { "_id" : 1, "name" : "10.0.3.43:27031", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1804, "optime" : { "ts" : Timestamp(1475812389, 2), "t" : NumberLong(2) }, "optimeDate" : ISODate("2016-10-07T03:53:09Z"), "electionTime" : Timestamp(1475811768, 1), "electionDate" : ISODate("2016-10-07T03:42:48Z"), "configVersion" : 8, "self" : true }, { "_id" : 2, "name" : "10.0.4.81:27031", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 1215, "optime" : { "ts" : Timestamp(1475812382, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2016-10-07T03:53:02Z"), "lastHeartbeat" : ISODate("2016-10-07T03:53:08.637Z"), "lastHeartbeatRecv" : ISODate("2016-10-07T03:53:08.642Z"), "pingMs" : NumberLong(2), "syncingTo" : "10.0.2.124:27031", "configVersion" : 8 }, { "_id" : 3, "name" : "10.0.2.124:27031", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 777, "optime" : { "ts" : Timestamp(1475812382, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2016-10-07T03:53:02Z"), "lastHeartbeat" : ISODate("2016-10-07T03:53:08.621Z"), "lastHeartbeatRecv" : ISODate("2016-10-07T03:53:08.631Z"), "pingMs" : NumberLong(0), "syncingTo" : "10.0.3.43:27031", "configVersion" : 8 } ], "ok" : 1 } csReplSet:PRIMARY>
あとは個別に起動しているmongodを停止していけばOKです。
7. Balancer再開
最後に、停止していたBalancerを再開させます。
mongos> sh.setBalancerState(true) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) mongos> sh.getBalancerState() true mongos>
以上で全ての手順が完了です。
まとめ
Ver.3.2からサポートされたConfigサーバのレプリカセットへの移行を試しました。WiredTigerへの移行も含め、公式のドキュメントにしっかりと移行の手順が記載されていますので、その通りに実施していけば問題ありません。
AWSの提供するCloudFormationテンプレートで構築したMongoDBクラスタを、最新バージョン・構成へ移行する手順を何回かに分けて紹介してきました。
今後も、MongoDBの新しいバージョンや新機能の追加があれば紹介していきたいと思います。